Driver Design of I2C Bus Device in Embedded Linux System

introduction

The I2C bus is a two-wire serial bus introduced by PHILIPS, which is used to connect the microcontroller and its peripheral devices. It is simple and highly efficient. Because its interface is directly above the components, the I2C bus occupies very little space, reducing the space of the circuit board and the number of chip pins, reducing the interconnection cost, and is particularly suitable for embedded products.

The Linux system has the advantages of open source, free, and abundant online resources, and has become the mainstream choice of embedded systems. Therefore, how to implement the I2C function in an embedded Linux system becomes a problem in actual development.

I2C bus

The I2C bus transfers information between devices connected to the bus through the serial data SDA and serial clock SCL lines, each device having a unique address identification. According to the different functions of data transmission, the devices are divided into master and slave. The host is a device that initializes the data transfer of the bus and generates a clock signal that allows transmission, usually a microcontroller. At this point, any addressed device is considered a slave, such as an LCD driver, E2PROM, and so on.

The I2C bus protocol specifies that each host must have a start, end, send data, and reply signal when communicating. These signals are the basic unit in the communication process. The start signal is the SDA line changing from high to low when the SCL line is high; the stop signal is the SDA line changing from low to high when the SCL line is high; the acknowledge signal is low when the SCL is high; the non-response signal Instead, SDA is high when SCL is high.

Each frame of data transmitted by the bus is 1 byte. The protocol stipulates that the high 7 bits of the first byte after starting the bus are the addressing address of the slave, and the 8th bit is the direction bit ("0" means the write operation of the master to the slave; "1" means the master For read operations from the slave, the remaining bytes are operational data. The data transfer process is: After the I2C bus sends the start signal, it sends the 7-bit addressing address of the slave and 1 bit of the read/write bit representing the nature of this operation. After the response signal arrives, the data is transmitted until the stop signal is sent. Every time the host sends 1 byte, it needs to detect whether there is an acknowledge signal on the SDA line, and if so, it will continue to send, otherwise it will stop sending data.

I2C bus driver structure in Linux

Linux systems have good support for the I2C bus. Corresponding to the hardware physical connection, the relationship between the various parts of the Linux I2C framework is shown in Figure 1.


Figure 1 Linux kernel I2C bus driver architecture

The I2C-related code in the kernel can be divided into three levels:

1. I2C core framework: provides core data structure definitions and related interface functions to implement I2C adapter driver and device driver registration and logout management, as well as I2C communication method upper layer and specific adapter-independent code for the system Each I2C bus adds a corresponding read and write method.

2. I2C bus adapter driver: Defines the i2c_adapter data structure that describes the specific I2C bus adapter and implements the I2C bus communication method on the specific I2C adapter, and is described by the i2c_algorithm data structure.

3. I2C device driver: define the i2c_client and possible private data structures that describe the specific device, use the function interface provided by the I2C core to complete the registration of the device in the kernel, and implement specific functions, including read, write, and ioctl operations on the user layer Interface.

In general, the I2C bus driver in Linux is divided into two parts: bus driver (BUS) and device driver (DEVICE). The I2C core and I2C bus adapter driver completes the host bus driver (BUS) on the hardware, while the I2C driver implements the slave device driver. In the design, the interface provided by I2C core is unified and does not need to be modified. We only need to implement specific I2C bus adapter driver and I2C device driver, which greatly improves the portability of the system.

The author used AT91RM9200 and X1227 to constitute the clock module of the embedded system in a certain product. In this design, AT91RM9200 is the host part of I2C and X1227 is the slave. Take this example as an example to introduce the implementation of these two parts.

AT91RM9200 I2C bus driver implementation

AT91RM9200 is ARM920T processor, it provides standard two-wire interface TWI, namely I2C interface, host operating mode. The I2C operation mode and status are set by the TWI control register TWI_CR. The clock is generated by the programmed value in register TWI_CWGR. This register defines the TWCK signal, adapting the interface to a wide range of clocks.

Specifically in the Linux AT91RM9200 I2C bus adapter driver implementation, first initialize the AT91RM9200 I2C work mode, and then load the I2C bus driver, which requires two structural modules to describe: struct i2c_adapter and struct i2c_algorithm.

Initialize the i2c_adapter structure member as follows:

Static struct i2c_adapter at91rm9200_adapter = {
Name: "AT91RM9200",
Id: I2C_ALGO_SMBUS,
Algo: &at91_algorithm,
Algo_data: NULL,
Inc_use: at91_inc,
Dec_use: at91_dec,
...
};

This module does not provide a read/write function. The specific read/write method is provided by the second module struct i2c_algorithm.

Static struct i2c_algorithm at91_algorithm = {
Name: "at91 i2c",
Id: I2C_ALGO_SMBUS,
Smbus_xfer: at91_smbus_xfer,
Master_xfer: at91_xfer,
Functionality: at91_func,
};

The two modules are registered to the operating system by calling the interface function i2c_add_adapter in the I2C core. The bus driver is even loaded. It can be seen that i2c_algorithm implements the specific method of i2c communication. For the at91rm9200 I2C adapter, at91_xfer is the most critical. Analyzes the kernel to know, the data transmission interface that I2C core frame offers to the host computer: I2c_master_send, i2c_master_recv, i2c_transfer is realized by calling at91_xfer finally.

The data transmission process is as follows: After the data transmission host initiates the Start state, it sends a 7-bit slave address to the DADR in the host mode register TWI_MMR to notify the slave device. The bit following the slave address indicates the direction of transmission (write or read). This bit is 0, indicating a write operation (send operation); if this bit is 1, it indicates a data read request (receive operation). TWI transmission requires the slave to give a reply after every byte received. In response to a clock pulse, the host releases the data line (HIGH) and the slave pulls down to generate a reply. The host polls the data line for this clock pulse and can poll the status bit using polling or interrupt mode. If the slave does not acknowledge the byte, the NAK bit of the status register TWI_SR will be set.

The write operation sends data to the holding register TWI_THR and sets the START bit of TWI_CR to start the transfer. The data is shifted in the internal shift register. When an acknowledgement is detected, TXRDY is set and the bit is cleared until new data is written in TWI_THR. The host generates a STOP condition to end the transfer. Set the start of reading sequence after START. When the RXRDY bit in the status register is set, the holding register (TWI_RHR) is received to receive one character. The RXRDY bit is reset when TWI_RHR is read.

The TWI interface can perform a variety of transmission formats: 7-bit slave address and 10-bit slave address. Three internal address bytes are configured through the host mode register TWI_MMR. If the slave only supports 7-bit address, IADRSZ must be set to 0. If the slave address is greater than 7 bits, the user must configure the address size IADRSZ and set the other slave address bits in the internal address register TWI_IADR.

X1227 device driver implementation

The X1227 is a real-time clock with a clock, calendar, CPU monitoring circuit, and two polling alarms. The clock uses a low-cost 32.768 kHz crystal as an input to accurately display the time in seconds, minutes, hours, days, weeks, months, and years. It automatically adjusts for leap year to 2096. At the same time the X1227 has a watchdog timer and 3 timeouts to choose from. In addition, the X1227 has a 4K bit EEPROM array that can be used as a memory for some user configuration data. The following uses the X1227 as an example to illustrate the design points of a specific I2C device driver.

As mentioned before, the I2C bus driver only provides a read and write mechanism for a bus and does not communicate itself. Communication is done by the I2C device driver. The device driver communicates with the specific device through the I2C bus. A device driver has two modules to describe, struct i2c_client and struct i2c_driver. I2c_client is used to describe a specific I2C device. The i2c_driver structure provides the communication between i2c_adapter and i2c_client.

Struct i2c_driver x1227_driver = {
Name: "x1227"
Id: I2C_DRIVERID_X1227,
Flags: I2C_DF_NOTIFY,
Attach_adapter: x1227_probe,
Detach_client: x1227_detach,
Command: x1227_command
};

Among them: attach_adapter uses the I2C bus access method provided by the adapter driver, and uses the address clue information provided in the device driver module to detect possible devices and their addresses. If the device is successfully discovered, a struct i2c_client is created to identify the device and register with the adapter's data structure. Detach_client is used to unregister the device from the bus and release i2c_client and the corresponding private data structure. Command is the underlying implementation of the ioctl function in the user interface.

The I2C device driver needs to implement two interfaces. One is the interface to the I2C core frame. When the device is initialized, it is called through the function i2c_add_driver to register the driver. Once this i2c_driver is loaded, the attach_adapter function will be called.

The other is the interface to the user application layer, providing the user program access to the I2C device interface, including interface functions that implement open, release, read, write, and most important ioctl and other standard file operations. Each device driver has a data structure called file_operations that implements interface functions.

Static struct file_operations rtc_fops = {
Owner: THIS_MODULE,
Ioctl: x1227_rtc_ioctl,
Open: x1227_rtc_open,
Release: x1227_rtc_release,
};

Open and release are used to open and close the X1227, and x1227_rtc_ioctl provides the user with a series of specific commands for controlling the clock chip: RTC_GET_TIME (time to read the real-time clock in a fixed data format), RTC_SET_TIME (set in a fixed data format) Real-time clock time) and E2PROM read and write.

For the X1227, it is generally registered as a miscdevice device (all miscdevice devices share a major device number, a different minor device number).

Static struct miscdevice x1227_rtc_miscdev = {
RTC_MINOR,
Tc?
&rtc_fops
};

At initialization, X1227 is registered with misc_register (&x1227_rtc_miscdev) so that the user program can access the X1227 through the device node /dev/rtc with the major number 10 device number 135.

To test the clock function of the X1227, first the I2C bus module and the X1227 module of the AT91RM9200 are loaded at system startup. It should be pointed out that Linux divides the clock into two kinds: system clock and hardware clock. The system clock refers to the clock in the current Linux Kernel, and the hardware clock is the motherboard-based hardware clock that is powered by the battery, which is X1227 in this article.

In Linux, the commands for clock viewing and setting are date and hwclock. First set the system clock, for example, set to 12:30 on August 17, 2006: date 081712302006, then set the hardware clock to the current system clock time, use the command /sbin/hwclock 衧ystohc, then the time in X1227 is set to the current system time. Then, usually when the operating system is started, the startup script /sbin/hwclock is set to ctosys, the system clock is updated with the time in X1227, and then the system clock is used to record the time until the system is restarted or shut down.

Conclusion

This article describes the I2C bus adapter and I2C device driver implementation. The design was successfully applied to the main control module of a network test equipment, realizing the real-time clock function of the equipment and facilitating the monitoring of the entire system. I2C bus is widely used in the current embedded field, such as audio/video control, storage device communication, and Linux has become the mainstream of embedded systems. From the perspective of the linux kernel, the I2C driver has a clear hierarchy and provides a framework for programmers to develop I2C-related drivers.

References :
1. Lessandro Rubini, Jonathan Corbet. Linux Device Drivers, second edition[M]. Oæ‚–eilly & Associates, 2002.
2. Zheng Xuyang, Li Bingbing, Huang Xinping, Research on Multi-Master Communication of Analog I2C Bus and Software Design, SCM and Embedded System Applications, 2005, 12:29_32
3. Philips Corporation, I2C bus specification version 2.1, 2000
4. Atmel Corporation, AT91RM9200 Datasheet, version E, 2005
5. Xicor Corporation, X1227 Datasheet, version1.3, 2004


Big Water Tank Vacuum Cleaner

Big Water Tank Vacuum Cleaner,Vacuum Cleaner,Vacuum Cleaner With Socket,Vacuum Cleaner For Roads

NingBo CaiNiao Intelligent Technology Co., LTD , https://www.intelligentnewbot.com